package my_interface

import (
	"fmt"
	"hash/crc32"
	"io"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/tarm/serial"
)

var (
	SerilPort *serial.Port
	err       error
	ack       bool
	buf       = make(chan byte, 4096)
	recBuffer = make([]byte, 4096)
)

func serialOpen(name string, buad int) (s *serial.Port, err error) {
	//设置串口编号
	c := &serial.Config{Name: name, Baud: buad}

	//打开串口
	s, err = serial.OpenPort(c)
	return
}

func serialRead() {
	for {
		n, err := SerilPort.Read(recBuffer)
		log.Println(recBuffer[:n])
		if n > 0 {
			for i := 0; i < n; i++ {
				buf <- recBuffer[i]
			}
			n = 0
		}
		if err != nil {
			if err != io.EOF {
				//Error Handler
			}
			break
		}
	}
}

func SendSeialCmd(cmd byte) {
	var (
		b   []byte
		crc uint32
	)
	b = append(b, 0x55) //头码
	b = append(b, 0x55) //头码
	b = append(b, 0)    //数据长度高位
	b = append(b, 0)    //数据长度低位
	b = append(b, cmd)  //指令
	crc = crc32.ChecksumIEEE(b[4:])
	b = append(b, byte(crc>>24))
	b = append(b, byte(crc>>16))
	b = append(b, byte(crc>>8))
	b = append(b, byte(crc>>0))

	b[2] = byte((len(b) - 4) >> 8)
	b[3] = byte((len(b) - 4) >> 0)

	// log.Println(b)
	SerilPort.Write(b)
}

func SendSeialData(cmd byte, data []byte) {
	var (
		b   []byte
		crc uint32
	)
	b = append(b, 0x55) //头码
	b = append(b, 0x55) //头码
	b = append(b, 0)    //数据长度高位
	b = append(b, 0)    //数据长度低位
	b = append(b, cmd)  //指令

	for i := 0; i < len(data); i++ {
		b = append(b, data[i])
	}

	crc = crc32.ChecksumIEEE(b[4:])
	b = append(b, byte(crc>>24))
	b = append(b, byte(crc>>16))
	b = append(b, byte(crc>>8))
	b = append(b, byte(crc>>0))

	b[2] = byte((len(b) - 4) >> 8)
	b[3] = byte((len(b) - 4) >> 0)

	// log.Println(b)
	SerilPort.Write(b)
}

func dataProcess() {
	var (
		length      int
		timeoutFlag bool = false
		count       int
		b           []byte
		crcB        []byte
	)

	go func() {
		for {
			//超时判断
			count++
			if (length-1) > len(buf) && count >= 50 {
				timeoutFlag = false
			}
			time.Sleep(time.Millisecond)
		}
	}()
	for {
		if timeoutFlag == true {
			//串口数据解析
			if len(buf) >= length {
				b = b[0:0]
				crcB = crcB[0:0]
				for i := 0; i < (length - 4); i++ {
					b = append(b, <-buf)
				}
				for i := (length - 4); i < length; i++ {
					crcB = append(crcB, <-buf)
				}

				c := uint32(crcB[0])<<24 | uint32(crcB[1])<<16 | uint32(crcB[2])<<8 | uint32(crcB[3])<<0
				crc := crc32.ChecksumIEEE(b)
				if crc == c {
					// fmt.Println(string(b[1:]))
					cmd := b[0]
					switch cmd {
					case 1:
						ack = true
					case 8:
						SendSeialData(3, []byte{0x8F, 0xDB, 0x44, 0x46, 0xD2}) //接收到MCU boot起始命令
						binBuf, err := ioutil.ReadFile(`project.bin`)
						if err != nil {
							fmt.Print(err)
						}
						wrFlash(binBuf)
					case 2:
						fmt.Println("写入完成")
					case 255:
						fmt.Println("写入错误")
					}
					timeoutFlag = false
				} else {
					fmt.Println("crc error")
				}
			}
		} else {
			if <-buf == 0x55 {
				if <-buf == 0x55 {
					lengthH := int(<-buf)
					lengthL := int(<-buf)
					length = lengthH<<8 | lengthL
					timeoutFlag = true
					count = 0
				}
			}
		}
	}
}

func SerialStart(name string, buad int) {
	SerilPort, err = serialOpen(name, buad)
	if err != nil {
		fmt.Println("串口打开失败")
		time.Sleep(time.Second)
		os.Exit(1)
	}

	go serialRead()
	go dataProcess()
}
